package br.edu.unicentro.mymib.entity;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.NoResultException;
import javax.persistence.OneToMany;
import javax.persistence.Query;

import org.hibernate.annotations.Cascade;

import br.edu.unicentro.mymib.base.EMFactory;
import br.edu.unicentro.mymib.base.EntityManagerService;

@Entity
@NamedQueries( {
		@NamedQuery(name = "post.findAll", query = "from Post as p"),
		@NamedQuery(name = "post.findByUsuario", query = "from Post as p where p.usuario = :usuario"),
		@NamedQuery(name = "post.findByEmailDeUsuario", query = "from Post as p where p.usuario.email = :email"),
		@NamedQuery(name = "post.findByData", query = "from Post as p where p.data between :dataInicio and :dataFim"),
		@NamedQuery(name = "post.findById", query = "from Post as p where p.id = :id") })
public final class Post {

	@Id
	@GeneratedValue
	private Long id;

	@ManyToMany(targetEntity = Tag.class, cascade = { CascadeType.PERSIST,
			CascadeType.MERGE })
	@JoinTable(name = "POST_TAG", joinColumns = @JoinColumn(name = "postId"), inverseJoinColumns = @JoinColumn(name = "tagId"))
	private Set<Tag> tags;

	@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
	@JoinTable(name = "POST_COMENTARIOS", joinColumns = @JoinColumn(name = "postId"), inverseJoinColumns = @JoinColumn(name = "comentarioId"))
	private List<Comentario> comentarios;

	@ManyToOne
	@JoinColumn(name = "usuarioId")
	private Usuario usuario;

	private String mensagem;
	private String assunto;
	private Date data;
	private int avaliacoesPositivas;
	private int avaliacoesNegativas;

	public Post() {
		this.tags = new HashSet<Tag>();
		this.comentarios = new ArrayList<Comentario>();
	}

	public Post(String assunto, String mensagem) {
		this.assunto = assunto;
		this.mensagem = mensagem;
		data = new Date();
		avaliacoesNegativas = 0;
		avaliacoesPositivas = 0;
		this.tags = new HashSet<Tag>();
		this.comentarios = new ArrayList<Comentario>();
	}

	private void salvar() throws Exception {
		EntityManagerService.salvar(this);
		// TODO verificar se nao vai criar outro post inves de comentar o mesmo
	}

	public void adicionarComentario(Comentario comentario) throws Exception {
		comentarios.add(comentario);
		EntityManagerService.salvar(this);
	}

	public void adicionarTag(String nomeTag) {
		Tag tag = Tag.buscarPorNome(nomeTag);
		tags.add(tag);
	}

	public Set<Tag> getTags() {
		return tags;
	}

	public List<Comentario> getComentarios() {
		return comentarios;
	}

	public String getMensagem() {
		return mensagem;
	}

	public String getAssunto() {
		return assunto;
	}

	public Date getData() {
		return data;
	}

	public int getAvaliacoesPositivas() {
		return avaliacoesPositivas;
	}

	public int getAvaliacoesNegativas() {
		return avaliacoesNegativas;
	}

	public void avaliarPositivamente() throws Exception {
		avaliacoesPositivas++;
		try {
			this.salvar();
		} catch (Exception e) {
			avaliacoesPositivas--;
			throw e;
		}
	}

	public void avaliarNegativamente() throws Exception {
		avaliacoesNegativas++;
		try {
			this.salvar();
		} catch (Exception e) {
			avaliacoesNegativas--;
			throw e;
		}
	}

	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public void setTags(Set<Tag> tags) {
		this.tags = tags;
	}

	public Usuario getUsuario() {
		return usuario;
	}

	public static List<Post> buscarTodos() {
		EntityManager em = EMFactory.getManager();
		Query query = em.createNamedQuery("post.findAll");
		try {
			return query.getResultList();
		} catch (NoResultException e) {
			return null;
		}
	}

	/*
	 * public static List<Post> buscarPorUsuario(Usuario usuario) {
	 * EntityManager em = EMFactory.getManager();
	 * 
	 * Query query = em.createNamedQuery("post.findByUsuario");
	 * query.setParameter("usuario", usuario);
	 * 
	 * try { return (List<Post>) query.getResultList(); } catch
	 * (NoResultException e) { return null; } }
	 */

	public static List<Post> buscarPorEmailDeUsuario(String email) {
		EntityManager em = EMFactory.getManager();

		Query query = em.createNamedQuery("post.findByEmailDeUsuario");
		query.setParameter("email", email);

		try {
			return query.getResultList();
		} catch (NoResultException e) {
			return null;
		}
	}

	public static Post buscarPorId(Long id) {
		EntityManager em = EMFactory.getManager();

		Query query = em.createNamedQuery("post.findById");
		query.setParameter("id", id);

		try {
			return (Post) query.getSingleResult();
		} catch (NoResultException e) {
			return null;
		}
	}

	public static List<Post> buscarPorData(Date dataInicio, Date dataFim) {
		EntityManager em = EMFactory.getManager();

		if (dataInicio == null)
			dataInicio = new Date(0);
		if (dataFim == null)
			dataFim = new Date();

		Query query = em.createNamedQuery("post.findByData");
		query.setParameter("dataInicio", dataInicio);
		query.setParameter("dataFim", dataFim);

		try {
			return query.getResultList();
		} catch (NoResultException e) {
			return null;
		}
	}

}